解决 pacote 打包 Bug
问题描述
Electron 应用使用 electron-builder 打包后运行,控制台报错:
TypeError: LRU is not a constructor
text
错误指向 node_modules 下的 hoist-get-in-for(或类似被提升的依赖包),该依赖在开发时运行正常,但打包后的应用中无法找到。
根因分析
问题链条
pacote 依赖 lru-cache → lru-cache 在 devDependencies 中(被提升到根 node_modules)
→ electron-builder 打包时仅包含 dependencies,排除 devDependencies
→ 打包后应用缺少 lru-cache → LRU is not a constructor
text
devDependencies vs dependencies 打包行为
| 依赖类型 | 开发环境 | 打包后 | 说明 |
|---|---|---|---|
dependencies | 可用 | 可用 | 打包时会被包含 |
devDependencies | 可用 | 不可用 | 打包时被排除 |
| 提升(hoisted)的依赖 | 可用 | 可能缺失 | 来自其他包的间接依赖 |
pnpm 与 npm/yarn 的差异
| 包管理器 | 依赖提升行为 | 打包影响 |
|---|---|---|
| npm | 所有依赖提升到根 node_modules | 可能引入幽灵依赖 |
| yarn | 类似 npm | 同上 |
| pnpm | 严格隔离,使用符号链接 | 不会出现幽灵依赖,但 public-hoist-pattern 可能导致问题 |
解决方案
方案一:显式声明缺失依赖(推荐)
将间接依赖显式添加到 dependencies 中:
# 查找哪个包依赖了 lru-cache
pnpm why lru-cache
# 显式添加到 dependencies
pnpm add lru-cache
bash
// package.json
{
"dependencies": {
"lru-cache": "^10.0.0",
"pacote": "^17.0.0"
}
}
json
方案二:配置 electron-builder 包含特定模块
// electron-builder.config.ts
import { Configuration } from 'electron-builder'
const config: Configuration = {
files: [
'!node_modules/**/{test,tests,__tests__,spec}/**',
'!node_modules/**/*.md',
'!node_modules/**/*.ts'
],
extraResources: [
{
from: 'node_modules/pacote',
to: 'node_modules/pacote',
filter: ['**/*']
}
],
// 确保以下依赖被包含
asarUnpack: [
'node_modules/pacote/**',
'node_modules/lru-cache/**'
]
}
export default config
typescript
方案三:Two package.json 结构
project/
├── package.json # 开发依赖(devDependencies)
├── app/
│ ├── package.json # 生产依赖(dependencies)—— 仅这些被打包
│ └── src/
└── electron-builder.yml
text
// 根 package.json(开发用)
{
"devDependencies": {
"electron": "^28.0.0",
"electron-builder": "^24.0.0"
},
"scripts": {
"postinstall": "electron-builder install-app-deps"
}
}
json
// app/package.json(打包用)
{
"name": "my-electron-app",
"dependencies": {
"pacote": "^17.0.0",
"lru-cache": "^10.0.0"
}
}
json
方案四:检查 pnpm 提升配置
# .npmrc
# 允许特定包被提升
public-hoist-pattern[]=*pacote*
public-hoist-pattern[]=*lru-cache*
yaml
调试技巧
# 1. 查看依赖树,找出幽灵依赖
pnpm why lru-cache
# 2. 检查打包后 app 目录是否包含目标模块
ls dist/mac-arm64/my-app.app/Contents/Resources/app/node_modules/
# 3. 使用 electron-builder 的文件追踪
DEBUG=electron-builder npx electron-builder build
# 4. 验证 asar 包内容
npx asar list dist/mac-arm64/my-app.app/Contents/Resources/app.asar | grep lru
bash
实践要点
- 打包后报
X is not a constructor的根本原因通常是依赖缺失,而非代码逻辑错误 - 使用
pnpm why <package>追溯间接依赖来源,确认是否为幽灵依赖 - 生产环境需要的包必须显式声明在
dependencies中,不能依赖提升机制 - Two package.json 结构是 electron-builder 推荐的最佳实践,能清晰分离开发与生产依赖
asarUnpack配置可以强制将特定模块从 asar 归档中解包,解决原生模块加载问题
↑